package org.bigfans.cloud.api.gateway.filter;

import com.bigfans.Constants;
import com.bigfans.framework.CurrentUser;
import com.bigfans.framework.utils.JsonUtils;
import com.bigfans.framework.utils.JwtUtils;
import com.bigfans.framework.utils.StringHelper;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.servlet.http.Cookie;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * @author lichong
 * @create 2018-07-31 下午9:53
 **/
@Component
public class AccessFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        HttpMethod method = request.getMethod();
        String path = request.getPath().value();
        if(path.contains("/login")){
            return chain.filter(exchange);
        }
        String authorization = this.extractAuthorization(request.getHeaders());
        String token = "";
        boolean hasAuth = false;
        Map<String, HttpCookie> cookies = request.getCookies().toSingleValueMap();
        if (authorization == null) {
            if (cookies != null) {
                String tmpToken = this.extraTempToken(cookies);
                if (tmpToken != null) {
                    hasAuth = true;
                    token = tmpToken;
                }
            }
        } else {
            if (authorization.length() > 7) {
                String HeadStr = authorization.substring(0, 6).toLowerCase();
                if (HeadStr.compareTo("bearer") == 0) {
                    token = authorization.substring(7, authorization.length());
                    if (StringHelper.isNotEmpty(token)) {
                        hasAuth = true;
                        cookies.remove(Constants.TOKEN.TMP_COOKIE_NAME);
                    }
                }
            }
        }
        if (!hasAuth) {
            token = this.createTempToken(UUID.randomUUID().toString());
            ResponseCookie responseCookie = ResponseCookie
                    .from(Constants.TOKEN.TMP_COOKIE_NAME, token)
                    .maxAge(60 * 60 * 24 * 7)
                    .domain("localhost")
                    .path("/")
                    .httpOnly(false)
                    .build();
            response.addCookie(responseCookie);
        }
        ServerHttpRequest requestWithToken = exchange.getRequest().mutate()
                .header(Constants.TOKEN.HEADER_KEY_NAME, token)
                .build();
        return chain.filter(exchange.mutate().request(requestWithToken).build());
    }



    protected String extractAuthorization(HttpHeaders headers){
        return headers.get(Constants.OAUTH.HEADER_KEY_NAME) == null ? null : headers.get(Constants.OAUTH.HEADER_KEY_NAME).get(0);
    }

    protected String extraTempToken(Map<String, HttpCookie> cookies){
        return cookies.get(Constants.TOKEN.TMP_COOKIE_NAME) == null ? null : cookies.get(Constants.TOKEN.TMP_COOKIE_NAME).getValue();
    }

    @Override
    public int getOrder() {
        return 0;
    }

    protected String createTempToken(String uid) {
        CurrentUser currentUser = new CurrentUser();
        currentUser.setAccount("tempUser");
        currentUser.setLoginTime(new Date());
        currentUser.setPeriod(60 * 60 * 24 * 7);
        currentUser.setType(CurrentUser.TYPE.TMP_USER);
        currentUser.setUid(uid);
        // 创建临时的token作为用户唯一凭证
        String tempToken = JwtUtils.create(JsonUtils.toJsonString(currentUser), Constants.TOKEN.JWT_SECURITY_KEY);
        return tempToken;
    }
}
